package com.loong.android.views;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.PopupWindow;

import com.loong.android.R;
import com.loong.android.utils.DrawableUtils;

/**
 * 弹窗视图(PopupView)，封装自Android原生的PopupWindow，可以将内容视图显示到指定视图的下方(或上方)
 */
public class PopupView {

    private final MyPopupWindow popupWindow;
    private boolean mInterceptOriginDismiss = false;

    /**
     * 构造新的弹窗
     */
    public PopupView() {
        popupWindow = new MyPopupWindow();
        initView();
    }

    /**
     * 通过上下文构造新的弹窗
     * @param context 上下文
     */
    public PopupView(Context context) {
        popupWindow = new MyPopupWindow(context);
        initView();
    }

    /**
     * 构造函数
     * @param contentView 内容视图
     */
    public PopupView(View contentView) {
        popupWindow = new MyPopupWindow(contentView);
        initView();
    }

    /**
     * @param width 宽度
     * @param height 高度
     */
    public PopupView(int width, int height) {
        popupWindow = new MyPopupWindow(width, height);
        initView();
    }

    public PopupView(View contentView, int width, int height) {
        popupWindow = new MyPopupWindow(contentView, width, height);
        initView();
    }

    public PopupView(View contentView, int width, int height, boolean focusable) {
        popupWindow = new MyPopupWindow(contentView, width, height, focusable);
        initView();
    }

    public MyPopupWindow getRawPopupWindow() {
        return popupWindow;
    }

    private void initView() {
        //默认设置透明颜色背景
        popupWindow.setBackgroundDrawable(new ColorDrawable(0));
        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        initEvent();
    }

    /**
     * 设置宽度
     * @param w 宽度值
     */
    public void setWidth(int w) {
        popupWindow.setWidth(w);
    }

    /**
     * 设置高度
     * @param h 高度值
     */
    public void setHeight(int h) {
        popupWindow.setHeight(h);
    }

    /**
     * 获取宽度
     */
    public int getWidth() {
        return popupWindow.getWidth();
    }

    /**
     * 获取高度
     */
    public int getHeight() {
        return popupWindow.getHeight();
    }

    /**
     * 设置内容的自定义视图
     * @param view 视图数据
     */
    public void setContentView(View view) {
        popupWindow.setContentView(view);
    }

    /**
     * 设置背景图片
     * @param context 上下文
     * @param resId 资源id
     */
    public void setBackground(Context context, int resId) {
        popupWindow.setBackgroundDrawable(DrawableUtils.from(context, resId));
    }

    /**
     * 设置背景图片
     * @param context 上下文
     * @param bitmap 位图数据
     */
    public void setBackground(Context context, Bitmap bitmap) {
        popupWindow.setBackgroundDrawable(DrawableUtils.from(context, bitmap));
    }

    /**
     * 设置背景图片，资源需要先获得读取文件的权限
     * @param context 上下文
     * @param filePath 文件路径
     */
    public void setBackground(Context context, String filePath) {
        popupWindow.setBackgroundDrawable(DrawableUtils.from(context, filePath));
    }


    /**
     * 设置背景图片
     * @param context 上下文
     * @param bytes 字节数组
     */
    public void setBackground(Context context, byte[] bytes) {
        popupWindow.setBackgroundDrawable(DrawableUtils.from(context, bytes));
    }

    /**
     * 是否正在显示
     */
    public boolean isShowing() {
        return popupWindow.isShowing();
    }

    /**
     * 是否可以获取焦点
     */
    public boolean isFocusable() {
        return popupWindow.isFocusable();
    }

    /**
     * 判断是否可以点击弹窗的外部
     */
    public boolean isOutsideTouchable() {
        return popupWindow.isOutsideTouchable();
    }

    /**
     * 是否显示在依赖视图的上方
     */
    public boolean isAboveAnchor() {
        return popupWindow.isAboveAnchor();
    }

    /**
     * 判断是否限定在父视图的内部，避免显示时超出父视图，导致内容显示补全
     */
    public boolean isAttachedInDecor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            return popupWindow.isAttachedInDecor();
        }
        return false;
    }

    /**
     * 显示在父视图的指定位置
     * @param parent 父视图对象
     * @param gravity 对齐方式
     * @param x 横向偏移
     * @param y 纵向偏移
     */
    public void showAtLocation(View parent, int gravity, int x, int y) {
        popupWindow.showAtLocation(parent, gravity, x, y);
    }

    /**
     * 作为下拉框显示
     * @param anchor 依赖的视图
     */
    public void showAsDropDown(View anchor) {
        popupWindow.showAsDropDown(anchor);
    }

    /**
     * 作为下拉框显示
     * @param anchor 依赖的视图对象
     * @param xoff 横向偏移
     * @param yoff 纵向偏移
     */
    public void showAsDropDown(View anchor, int xoff, int yoff) {
        popupWindow.showAsDropDown(anchor, xoff, yoff);
    }

    /**
     * 作为下拉框显示
     * @param anchor 依赖的视图
     * @param xoff 横向偏移
     * @param yoff 纵向偏移
     * @param gravity 对齐方式
     */
    public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            popupWindow.showAsDropDown(anchor, xoff, yoff, gravity);
        }
    }

    /**
     * 关闭
     */
    public void dismiss() {
        popupWindow.callDismiss();
    }

    /**
     * 是否限制在父视图的内部，不允许超出父视图，避免出现显示内容被遮挡的情况
     * @param enabled 是否启用
     */
    public void setAttachedInDecor(boolean enabled) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            popupWindow.setAttachedInDecor(enabled);
        }
    }

    /**
     * 设置对话框的海拔，存在海拔时可产生阴影。注意需要api>=21才能使用
     * @param elevation 海拔高度
     */
    public void setElevation(float elevation) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            popupWindow.setElevation(elevation);
        }
    }

    /**
     * 设置能否获取焦点
     * @param focusable 可否
     */
    public void setFocusable(boolean focusable) {
        popupWindow.setFocusable(focusable);
    }

    /**
     * 当作为下拉框显示时，是否覆盖于依赖的视图上
     * @param overlapAnchor 是否覆盖
     */
    public void setOverlapAnchor(boolean overlapAnchor) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            popupWindow.setOverlapAnchor(overlapAnchor);
        }
    }

    /**
     * 设置是否可以点击弹窗的外部。需要调用：setFocusable(false)才有效
     * @param touchable 可否点击
     */
    public void setOutsideTouchable(boolean touchable) {
        popupWindow.setOutsideTouchable(touchable);
    }

    /**
     * 设置是否可以触发触摸事件
     * @param touchable 可否
     */
    public void setTouchable(boolean touchable) {
        popupWindow.setTouchable(touchable);
    }

    /**
     * 判断作为下拉框显示时，是否覆盖于依赖视图的上方
     */
    public boolean getOverlapAnchor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return popupWindow.getOverlapAnchor();
        }
        return false;
    }

    /**
     * 取弹窗的海拔高度
     */
    public float getElevation() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return popupWindow.getElevation();
        }
        return 0;
    }

    /**
     * 计算当作为下拉框时可显示的最大高度
     * @param anchor 依赖的视图
     */
    public int getMaxAvailableHeight(View anchor) {
        return popupWindow.getMaxAvailableHeight(anchor);
    }

    /**
     * 计算当作为下拉框时可显示的最大高度
     * @param anchor 依赖的视图
     * @param yOffset 纵向偏移
     */
    public int getMaxAvailableHeight(View anchor, int yOffset) {
        return popupWindow.getMaxAvailableHeight(anchor, yOffset);
    }

    /**
     * 计算当作为下拉框时可显示的最大高度
     * @param anchor 依赖的视图
     * @param yOffset 纵向偏移
     */
    public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return popupWindow.getMaxAvailableHeight(anchor, yOffset, ignoreBottomDecorations);
        }
        return 0;
    }

    /**
     * 取弹窗内容视图对象
     */
    public View getContentView() {
        return popupWindow.getContentView();
    }

    /**
     * 更新弹窗
     */
    public void update() {
        popupWindow.update();
    }

    /**
     * 更新弹窗
     * @param width 新的宽度
     * @param height 新的高度
     */
    public void update(int width, int height) {
        popupWindow.update(width, height);
    }

    /**
     * 更新弹窗
     * @param anchor 依赖的视图
     * @param width 新的宽度
     * @param height 新的高度
     */
    public void update(View anchor, int width, int height) {
        popupWindow.update(anchor, width, height);
    }

    /**
     * 更新弹窗
     * @param x 横坐标
     * @param y 纵坐标
     * @param width 新的宽度
     * @param height 新的高度
     */
    public void update(int x, int y, int width, int height) {
        popupWindow.update(x, y, width, height);
    }

    /**
     * 更新弹窗
     * @param anchor 依赖的对象
     * @param xoff 横向偏移
     * @param yoff 纵向偏移
     * @param width 新的宽度
     * @param height 新的高度
     */
    public void update(View anchor, int xoff, int yoff, int width, int height) {
        popupWindow.update(anchor, xoff, yoff, width, height);
    }

    /**
     * 设置是否将弹窗限制在屏幕范围内。
     * @param enable 若为true，则限制弹窗只能在屏幕范围内显示；为false，则可以显示到屏幕边界之外
     */
    public void setClippingEnabled(boolean enable) {
        popupWindow.setClippingEnabled(enable);
    }

    /**
     * 判断是否将弹窗限制在屏幕范围内。
     */
    public boolean isClippingEnabled() {
        return popupWindow.isClippingEnabled();
    }

    /**
     * 设置动画类型，若弹窗正在显示，需要调用update函数才有效果，否则需要下次显示才有效果。
     * @param type 类型，参考AnimateType
     */
    public void setAnimate(int type) {
        switch (type) {
            case AnimateType.NONE:
                popupWindow.setAnimationStyle(0);
                break;
            case AnimateType.FADE:
                popupWindow.setAnimationStyle(-1);
                break;
            case AnimateType.FROM_LEFT:
                popupWindow.setAnimationStyle(R.style.loong_popup_dialog_animation_left);
                break;
            case AnimateType.FROM_RIGHT:
                popupWindow.setAnimationStyle(R.style.loong_popup_dialog_animation_right);
                break;
            case AnimateType.FROM_TOP:
                popupWindow.setAnimationStyle(R.style.loong_popup_dialog_animation_top);
                break;
            case AnimateType.FROM_BOTTOM:
                popupWindow.setAnimationStyle(R.style.loong_popup_dialog_animation_bottom);
                break;
        }
    }

    /**
     * 置弹窗被关闭的事件回调
     * @param event 事件回调
     */
    public void setDismissEvent(DismissEvent event) {
        this.mDismissEvent = event;
    }

    /**
     * 是否拦截所有原生弹窗视图(PopupView)的关闭处理，自行实现关闭逻辑
     * @param isIntercept 是否拦截
     */
    public void setInterceptOriginDismiss(boolean isIntercept) {
        this.mInterceptOriginDismiss = isIntercept;
    }

    /**
     * 获取是否拦截所有原生弹窗视图(PopupView)的关闭处理
     */
    public boolean getIsInterceptOriginDismiss() {
        return mInterceptOriginDismiss;
    }

    /**
     * 设置输入法的模式
     * @param mode 模式
     */
    public void setInputMethodMode(int mode) {
        popupWindow.setInputMethodMode(mode);
    }

    /**
     * 获取输入法的模式
     */
    public int getInputMethodMode() {
        return popupWindow.getInputMethodMode();
    }

    /**
     * 设置软键盘的模式
     * @param mode 模式
     */
    public void setSoftInputMode(int mode) {
        popupWindow.setSoftInputMode(mode);
    }

    /**
     * 获取软键盘的模式
     */
    public int getSoftInputMode() {
        return popupWindow.getSoftInputMode();
    }

    private DismissEvent mDismissEvent;

    private void initEvent() {
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                if(mDismissEvent != null) mDismissEvent.onDismiss();
            }
        });
    }

    /**
     * 弹窗被关闭的接口事件
     */
    public abstract static class DismissEvent {
        /**
         * 弹窗被关闭
         */
        public void onDismiss() { }
    }

    /**
     * 动画类型表
     */
    public static class AnimateType {
        //无动画
        public final static int NONE = 0;
        //淡入淡出
        public final static int FADE = 1;
        //从左侧滑入滑出
        public final static int FROM_LEFT = 2;
        //从右侧滑入滑出
        public final static int FROM_RIGHT = 3;
        //从上部滑入滑出
        public final static int FROM_TOP = 4;
        //从下部滑入滑出
        public final static int FROM_BOTTOM = 5;
    }

    /**
     * 输入方法表
     */
    public static class InputMethodMode {
        /**
         * 根据弹窗视图(PopupView)是否可获取焦点来判断是否显示输入法
         */
        public final static int FROM_FOCUSABLE = PopupWindow.INPUT_METHOD_FROM_FOCUSABLE;
        /**
         * 始终显示输入法，不管弹窗视图(PopupView)是否可获取焦点
         */
        public final static int NEEDED = PopupWindow.INPUT_METHOD_NEEDED;
        /**
         * 始终不显示输入法，不管弹窗视图(PopupView)是否可获取焦点
         */
        public final static int NOT_NEEDED = PopupWindow.INPUT_METHOD_NOT_NEEDED;
    }

    private class MyPopupWindow extends PopupWindow {
        public MyPopupWindow(Context context) {
            super(context);
        }

        public MyPopupWindow(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public MyPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        public MyPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }

        public MyPopupWindow() {
        }

        public MyPopupWindow(View contentView) {
            super(contentView);
        }

        public MyPopupWindow(int width, int height) {
            super(width, height);
        }

        public MyPopupWindow(View contentView, int width, int height) {
            super(contentView, width, height);
        }

        public MyPopupWindow(View contentView, int width, int height, boolean focusable) {
            super(contentView, width, height, focusable);
        }

        @Override
        public void showAsDropDown(View anchor) {
            super.showAsDropDown(anchor);
        }

        @Override
        public void dismiss() {
            //拦截原生的dismiss方法，屏蔽所有原生PopupWindow控制的关闭效果，自行实现关闭PopupWindow
            if(mInterceptOriginDismiss) return;
            super.dismiss();
        }
        public void callDismiss() {
            super.dismiss();
        }
    }
}
